﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace PS3Helpers.Helpers
{
    internal enum ProcessStreamReadType { StandardError, StandardOutput }

    internal sealed class StreamReaderThread : ThreadBase, IDisposable
    {
        private readonly Process _process;
        private StreamReader _reader = null;
        private readonly StringBuilder _target;

        internal StreamReaderThread(Process process, ProcessStreamReadType readtype, StringBuilder target)
        {
            _process = process;
            _target = target;

            switch (readtype)
            {
                case ProcessStreamReadType.StandardError:
                    {
                        if (_process.StartInfo.RedirectStandardError)
                        {
                            _reader = _process.StandardError;
                        }
                        break;
                    }
                case ProcessStreamReadType.StandardOutput:
                    {
                        if (_process.StartInfo.RedirectStandardOutput)
                        {
                            _reader = _process.StandardOutput;
                        }
                        break;
                    }
            }

            Start();
        }

        #region IDisposable implementation

        ~StreamReaderThread()
        {
            Dispose(true);
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        private bool _disposed = false;
        public void Dispose(bool disposing)
        {
            lock (this)
            {
                if (!_disposed)
                {
                    try
                    {
                        if (disposing)
                        {
                            // Release managed components
                            if (_reader != null)
                            {
                                _reader.Close();
                                _reader = null;
                            }
                        }

                        // Release unmanaged components
                        // ...
                    }
                    finally
                    {
                        _disposed = true;
                    }
                }
            }
        }

        #endregion IDisposable implementation

        protected override void Execute()
        {
            if (_reader == null)
                return;

            const int BufferSize = 512;
            char[] buff = new char[BufferSize];

            while (true)
            {
                try
                {
                    int num = _reader.Read(buff, 0, BufferSize);
                    if (num <= 0)
                    {
                        if (_process.HasExited) // If process has finished.
                            break;
                        continue;
                    }

                    _target.Append(new string(buff, 0, num));
                }
                catch (Exception e)
                {
                    // Will probably never happen, but in case.
                }
                
                Thread.Sleep(10);
            }
        }
    }
}
